﻿using System;
using System.Collections.Generic;
using Microsoft.SharePoint;

namespace GDExtensions
{
    /// <summary>
    /// Structure for the "Run As Admin" methods
    /// </summary>
    public struct InputParameters
    {
        private SPSite _elevatedSite;
        private SPWeb _elevatedWeb;
        private object[] _inputArgs;

        /// <summary>
        /// Elevated site
        /// </summary>
        public SPSite ElevatedSite { get { return _elevatedSite; } }

        /// <summary>
        /// Elevated web
        /// </summary>
        public SPWeb ElevatedWeb { get { return _elevatedWeb; } }

        /// <summary>
        /// Input parameters to pass to the method
        /// </summary>
        public object[] InputArgs { get { return _inputArgs; } }

        /// <summary>
        /// Constructure for the InputParmaters structure
        /// </summary>
        /// <param name="elevatedSite">Elevated site to pass to the method</param>
        /// <param name="elevatedWeb">Elevated web to pass to the method</param>
        /// <param name="inputArgs">Optional input parameters</param>
        public InputParameters(SPSite elevatedSite, SPWeb elevatedWeb, params object[] inputArgs)
        {
            // Save the elevated site/web & input arguments
            _elevatedSite = elevatedSite;
            _elevatedWeb = elevatedWeb;
            _inputArgs = inputArgs;
        }
    }

    /// <summary>
    /// Associated security groups:
    /// Owners, Members, Visitors
    /// </summary>
    public enum AssociatedSecurityGroups
    {
        /// <summary>
        /// Default members group
        /// </summary>
        Members = 0,
        /// <summary>
        /// Default owners group
        /// </summary>
        Owners,
        /// <summary>
        /// Default visitors group
        /// </summary>
        Visitors
    };

    /// <summary>
    /// Extension methods for the <see cref="T:Microsoft.SharePoint.SPWeb"/> class.
    /// </summary>
    /// <remarks></remarks>
    public static class SPWebExtensions
    {
        #region Public Methods
        /// <summary>
        /// Method to add the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPRoleType"/> role for the <paramref name="group"/>.</param>
        /// <returns><c>true</c> if <paramref name="groupName"/> is added successfully; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static bool AddSecurityGroup(this SPWeb web, string groupName, SPRoleType roleType)
        {
            // Add the security group
            return web.AddSecurityGroup(web.GetSecurityGroup(groupName), roleType);
        }

        /// <summary>
        /// Method to add the <paramref name="group"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to add.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPRoleType"/> role for the <paramref name="group"/>.</param>
        /// <returns><c>true</c> if <paramref name="group"/> is added successfully; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static bool AddSecurityGroup(this SPWeb web, SPGroup group, SPRoleType roleType)
        {
            // Ensure the group exists
            if (group != null)
            {
                // Add the security group
                return web.AddSecurityGroup(group, web.RoleDefinitions.GetByType(roleType));
            }
            return false;
        }

        /// <summary>
        /// Method to add the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="roleDefinition">The <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/> role definition for the <paramref name="group"/>.</param>
        /// <returns><c>true</c> if <paramref name="groupName"/> is added successfully; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static bool AddSecurityGroup(this SPWeb web, string groupName, SPRoleDefinition roleDefinition)
        {
            // Add the security group
            return web.AddSecurityGroup(web.GetSecurityGroup(groupName), roleDefinition);
        }

        /// <summary>
        /// Method to add the <paramref name="group"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to add.</param>
        /// <param name="roleDefinition">The <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/> role definition for the <paramref name="group"/>.</param>
        /// <returns><c>true</c> if <paramref name="group"/> is added successfully; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static bool AddSecurityGroup(this SPWeb web, SPGroup group, SPRoleDefinition roleDefinition)
        {
            // Call the private method
            return _AddSecurityGroup(web, group, roleDefinition);
        }

        /// <summary>
        /// Method to clear the web permissions.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <remarks></remarks>
        public static void ClearPermissions(this SPWeb web)
        {
            // Call the private method
            _ClearPermissions(web);
        }

        /// <summary>
        /// Method to copy the branding from the parent web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="shareNavigation">The use shared navigation flag.</param>
        public static void CopyBrandingFromParent(this SPWeb web, bool shareNavigationFl)
        {
            // Call the private method
            _CopyBrandingFromParent(web, shareNavigationFl);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType)
        {
            // Create the security group
            return web.CreateSecurityGroup(groupName, description, roleType, false);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="ownersGroup">The owner of the <paramref name="groupName"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            SPGroup ownersGroup)
        {
            // Create the security group
            return web.CreateSecurityGroup(groupName, description, roleType, ownersGroup, false);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="owner">The owner of the <paramref name="groupName"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            SPUser owner)
        {
            // Create the security group
            return web.CreateSecurityGroup(groupName, description, roleType, null, owner, false);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="deleteExisting">if set to <c>true</c> deletes the existing <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            bool deleteExisting)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return default(SPGroup); }

            // Get the associated owners group
            SPGroup ownersGroup = web.GetAssociatedSecurityGroup(AssociatedSecurityGroups.Owners);
            if (ownersGroup != null)
            {
                return web.CreateSecurityGroup(groupName, description, roleType, ownersGroup, deleteExisting);
            }
            else if (web.Site.Owner != null)
            {
                return web.CreateSecurityGroup(groupName, description, roleType, web.Site.Owner, deleteExisting);
            }

            return default(SPGroup);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="owner">The owner of the <paramref name="groupName"/>.</param>
        /// <param name="deleteExisting">if set to <c>true</c> deletes the existing <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            SPGroup ownersGroup, bool deleteExisting)
        {
            return web.CreateSecurityGroup(groupName, description, roleType, ownersGroup, null, deleteExisting);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="owner">The owner of the <paramref name="groupName"/>.</param>
        /// <param name="deleteExisting">if set to <c>true</c> deletes the existing <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            SPUser owner, bool deleteExisting)
        {
            return web.CreateSecurityGroup(groupName, description, roleType, null, owner, deleteExisting);
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="ownersGroup">The owner of the <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <param name="owner">The owner of the <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPUser"/>.</param>
        /// <param name="deleteExisting">if set to <c>true</c> deletes the existing <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup CreateSecurityGroup(this SPWeb web, string groupName, string description, SPRoleType roleType,
            SPGroup ownersGroup, SPUser owner, bool deleteExisting)
        {
            // Call the private method
            return _CreateSecurityGroup(web, groupName, description, roleType, ownersGroup, owner, deleteExisting);
        }

        /// <summary>
        /// Method to delete the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static void DeleteSecurityGroup(this SPWeb web, string groupName)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return; }

            // Parse the site groups
            foreach (SPGroup siteGroup in web.SiteGroups)
            {
                // See if the group name exists
                if (siteGroup.Name.Equals(groupName, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Delete the group
                    web.DeleteSecurityGroup(siteGroup);

                    // Break from the loop
                    break;
                }
            }
        }

        /// <summary>
        /// Method to delete the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to delete.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static void DeleteSecurityGroup(this SPWeb web, SPGroup group)
        {
            // Call the private method
            _DeleteSecurityGroup(web, group);
        }

        /// <summary>
        /// Method to determine if a file exists.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="url">The url of the file.</param>
        /// <returns>The file.</returns>
        public static SPFile FileExists(this SPWeb web, string url)
        {
            // Call the private method
            return _FileExists(web, url);
        }

        /// <summary>
        /// Method to get the <paramref name="associatedSecurityGroup"/> for the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="associatedSecurityGroup">The <see cref="AssociatedSecurityGroups"/> type.</param>
        /// <returns>The <paramref name="AssociatedSecurityGroups"/> <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup GetAssociatedSecurityGroup(this SPWeb web, AssociatedSecurityGroups associatedSecurityGroup)
        {
            // Call the private method
            return _GetAssociatedSecurityGroup(web, associatedSecurityGroup);
        }

        /// <summary>
        /// Method to find the <paramref name="roleName"/> in the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="roleName">The name of the <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/>.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/>.</returns>
        /// <remarks></remarks>
        public static SPRoleDefinition GetRoleDefinitionByName(this SPWeb web, string roleName)
        {
            // Call the private method
            return _GetRoleDefinitionByName(web, roleName);
        }

        /// <summary>
        /// Method to get the <paramref name="name"/> security group in the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static SPGroup GetSecurityGroup(this SPWeb web, string groupName)
        {
            // Call the private method
            return _GetSecurityGroup(web, groupName);
        }

        /// <summary>
        /// Method to processes the batch methods, using the template created in the <see cref="CreateMethodTemplate(SPList)"/> method.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methods">The method templates to process.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static string ProcessBatchMethods(this SPWeb web, string methods)
        {
            // Call the private method
            return _ProcessBatchMethods(web, methods);
        }

        /// <summary>
        /// Method to remove the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static void RemoveSecurityGroup(this SPWeb web, string groupName)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return; }

            // Parse the site groups
            foreach (SPGroup siteGroup in web.SiteGroups)
            {
                // See if the group name exists
                if (siteGroup.Name.Equals(groupName, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Remove the group
                    web.RemoveSecurityGroup(siteGroup);

                    // Break from the loop
                    break;
                }
            }
        }

        /// <summary>
        /// Method to remove the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to remove.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        public static void RemoveSecurityGroup(this SPWeb web, SPGroup group)
        {
            // Call the private method
            _RemoveSecurityGroup(web, group);
        }

        /// <summary>
        /// Method to elevate and run the <paramref name="methodToElevate"/> as an administrator, against the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methodToElevate">The method to elevate.</param>
        /// <remarks></remarks>
        public static void RunAsAdmin(this SPWeb web, Action<SPWeb> methodToElevate)
        {
            // Call the private method
            _RunAsAdmin(web, methodToElevate);
        }

        /// <summary>
        /// Method to elevate and run the <paramref name="methodToElevate"/> as an administrator, against the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methodToElevate">The method to elevate.</param>
        /// <param name="inputArgs">The <see cref="InputParameters"/> for <paramref name="methodToElevate"/>.</param>
        /// <returns>Return object from the <paramref name="methodToElevate"/>.</returns>
        /// <remarks></remarks>
        public static object RunAsAdmin(this SPWeb web, Func<InputParameters, object> methodToElevate, params object[] inputArgs)
        {
            // Call the private method
            return _RunAsAdmin(web, methodToElevate, inputArgs);
        }

        /// <summary>
        /// Method to update the master page.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="masterPageUrl">The master page url.</param>
        /// <param name="siteLogoDescription">The site logo description.</param>
        /// <param name="siteLogoUrl">The site logo url.</param>
        /// <param name="uiVersionNumber">The UI Version number.</param>
        /// <param name="updateSubWebsFl">The flag to update all sub-webs.</param>
        public static void UpdateMasterPage(this SPWeb web, string masterPageUrl,
            string siteLogoDescription, string siteLogoUrl, int uiVersionNumber, bool updateSubWebsFl)
        {
            // Update the master page
            web.UpdateMasterPage(masterPageUrl, masterPageUrl, siteLogoDescription, siteLogoUrl, uiVersionNumber, updateSubWebsFl);
        }

        /// <summary>
        /// Method to update the master page.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="customMasterUrl">The custom master page url.</param>
        /// <param name="masterPageUrl">The master page url.</param>
        /// <param name="siteLogoDescription">The site logo description.</param>
        /// <param name="siteLogoUrl">The site logo url.</param>
        /// <param name="uiVersionNumber">The UI Version number.</param>
        /// <param name="updateSubWebsFl">The flag to update all sub-webs.</param>
        public static void UpdateMasterPage(this SPWeb web, string customMasterUrl, string masterPageUrl,
            string siteLogoDescription, string siteLogoUrl, int uiVersionNumber, bool updateSubWebsFl)
        {
            // Call the private method
            _UpdateMasterPage(web, customMasterUrl, masterPageUrl, siteLogoDescription, siteLogoUrl, uiVersionNumber, updateSubWebsFl);
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Method to add the <paramref name="group"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to add.</param>
        /// <param name="roleDefinition">The <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/> role definition for the <paramref name="group"/>.</param>
        /// <returns><c>true</c> if <paramref name="group"/> is added successfully; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        private static bool _AddSecurityGroup(SPWeb web, SPGroup group, SPRoleDefinition roleDefinition)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return false; }

            // Ensure the group and role def exist
            if (group != null && roleDefinition != null)
            {
                // Create the role assignment
                SPPrincipal principal = group as SPPrincipal;
                SPRoleAssignment assignment = new SPRoleAssignment(principal);

                // Add the role definition
                assignment.RoleDefinitionBindings.Add(roleDefinition);

                // See if this is not the root web, and is still inheriting from permissions from its parent
                if (!web.IsRootWeb && !web.HasUniqueRoleAssignments)
                {
                    // Break role inheritence for this web
                    web.BreakRoleInheritance(true);
                }

                // Parse the role assignments for this web
                for (int i = 0; i < web.RoleAssignments.Count; i++)
                {
                    // See if this role assignment is for this group
                    if (web.RoleAssignments[i].Member.ID == group.ID)
                    {
                        // Remove this role assignment
                        web.RoleAssignments.Remove(i);
                    }
                }

                // Add the group to the list
                web.RoleAssignments.Add(assignment);

                // Return success
                return true;
            }

            // Return false by default
            return false;
        }

        /// <summary>
        /// Method to clear the web permissions.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <remarks></remarks>
        private static void _ClearPermissions(SPWeb web)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return; }

            // Ensure the web contains role assignments
            if (web.RoleAssignments.Count < 1) { return; }

            // Break the role inheritance
            web.BreakRoleInheritance(false);

            // Parse the role assignments
            for (int i = web.RoleAssignments.Count - 1; i >= 0; i--)
            {
                // Clear the current role assignement
                web.RoleAssignments.Remove(i);
            }

            // Get the associated owners group
            SPGroup ownersGroup = web.GetAssociatedSecurityGroup(AssociatedSecurityGroups.Owners);
            if (ownersGroup != null)
            {
                // Add the owners group by default, and give it full control
                web.AddSecurityGroup(ownersGroup, SPRoleType.Administrator);
            }
        }

        /// <summary>
        /// Method to copy the branding from the parent web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="shareNavigation">The use shared navigation flag.</param>
        private static void _CopyBrandingFromParent(SPWeb web, bool shareNavigationFl)
        {
            // Ensure the web exists, and the parent web exists
            if (web == null || !web.Exists || web.ParentWeb == null) { return; }

            // Copy the parent branding
            web.AlternateCssUrl = web.ParentWeb.AlternateCssUrl;
            web.CustomMasterUrl = web.ParentWeb.CustomMasterUrl;
            web.MasterUrl = web.ParentWeb.MasterUrl;
            web.SiteLogoDescription = web.ParentWeb.SiteLogoDescription;
            web.SiteLogoUrl = web.ParentWeb.SiteLogoUrl;

            // Set the share navigation flag
            web.Navigation.UseShared = shareNavigationFl;

            // Update the web
            web.Update();
        }

        /// <summary>
        /// Method to create the <paramref name="groupName"/> to the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/> group.</param>
        /// <param name="description">The <see cref="T:Microsoft.SharePoint.SPGroup"/> description.</param>
        /// <param name="roleType">The <see cref="T:Microsoft.SharePoint.SPGroup"/> <see cref="T:Microsoft.SharePoint.SPRoleType"/>.</param>
        /// <param name="ownersGroup">The owner of the <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <param name="owner">The owner of the <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPUser"/>.</param>
        /// <param name="deleteExisting">if set to <c>true</c> deletes the existing <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <paramref name="groupName"/> as a <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        private static SPGroup _CreateSecurityGroup(SPWeb web, string groupName, string description, SPRoleType roleType,
            SPGroup ownersGroup, SPUser owner, bool deleteExisting)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return default(SPGroup); }

            // Get the security group
            SPGroup group = GetSecurityGroup(web, groupName);

            // See if the group name exists
            if (group != null)
            {
                // See if we are deleting the existing group
                if (deleteExisting)
                {
                    // Remove the security group
                    web.RemoveSecurityGroup(group);
                }
                else
                {
                    // Return the existing group
                    return group;
                }
            }

            // Ensure the owners group exists
            if (ownersGroup != null || owner != null)
            {
                // Add the group to the site groups
                web.SiteGroups.Add(groupName, ownersGroup == null ? (SPMember)owner : ownersGroup, null, description);

                // Get the group
                group = web.SiteGroups[groupName];

                // Add the role type
                if (roleType != SPRoleType.None)
                {
                    // See if this is not the root web, and is still inheriting from permissions from its parent
                    if (!web.IsRootWeb && !web.HasUniqueRoleDefinitions)
                    {
                        web.BreakRoleInheritance(true);
                    }

                    // Create the role assignment
                    SPRoleDefinition roleDef = web.RoleDefinitions.GetByType(roleType);

                    // Assign the role to the group
                    SPRoleAssignment assignment = new SPRoleAssignment(group);
                    assignment.RoleDefinitionBindings.Add(roleDef);

                    // Update the web
                    web.RoleAssignments.Add(assignment);
                    web.Update();
                }
            }

            // Return the group
            return group;
        }

        /// <summary>
        /// Method to delete the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to delete.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        private static void _DeleteSecurityGroup(SPWeb web, SPGroup group)
        {
            // Ensure the web & group objects exists
            if (web != null && group != null)
            {
                // Delete the group
                web.SiteGroups.RemoveByID(group.ID);
            }
        }

        /// <summary>
        /// Method to determine if a file exists.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="url">The url of the file.</param>
        /// <returns>The file.</returns>
        private static SPFile _FileExists(SPWeb web, string url)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return default(SPFile); }

            // Get the file
            SPFile file = web.GetFile(url);

            // See if the file exists
            if (file != null && file.Exists) { return file; }

            // See if a parent web exists
            if (web.ParentWeb != null)
            {
                // See if the file exists in the parent web
                return web.ParentWeb.FileExists(url);
            }

            return default(SPFile);
        }

        /// <summary>
        /// Method to get the <paramref name="associatedSecurityGroup"/> for the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="associatedSecurityGroup">The <see cref="AssociatedSecurityGroups"/> type.</param>
        /// <returns>The <paramref name="AssociatedSecurityGroups"/> <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        private static SPGroup _GetAssociatedSecurityGroup(SPWeb web, AssociatedSecurityGroups associatedSecurityGroup)
        {
            SPGroup group = default(SPGroup);

            // Ensure the web exists
            if (web == null || !web.Exists) { return group; }

            // Set the group
            // Members
            if (associatedSecurityGroup == AssociatedSecurityGroups.Members)
            {
                group = web.AssociatedMemberGroup;
            }
            // Owners
            else if (associatedSecurityGroup == AssociatedSecurityGroups.Owners)
            {
                group = web.AssociatedOwnerGroup;
            }
            // Visitors
            else
            {
                group = web.AssociatedVisitorGroup;
            }

            // See if the group does not exist and a parent web exists
            if (group == null && web.ParentWeb != null)
            {
                // Get the associated security group from the parent web
                group = web.ParentWeb.GetAssociatedSecurityGroup(associatedSecurityGroup);
            }

            return group;
        }

        /// <summary>
        /// Method to find the <paramref name="roleName"/> in the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="roleName">The name of the <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/>.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPRoleDefinition"/>.</returns>
        /// <remarks></remarks>
        private static SPRoleDefinition _GetRoleDefinitionByName(SPWeb web, string roleName)
        {
            // Ensure the web exists
            if (web != null && web.Exists)
            {
                // Parse the role definitions
                foreach (SPRoleDefinition roleDefinition in web.RoleDefinitions)
                {
                    // See if this is the role def we are looking for
                    if (roleDefinition.Name.Equals(roleName, StringComparison.CurrentCultureIgnoreCase))
                    {
                        // Return the role definition
                        return roleDefinition;
                    }
                }
            }

            return default(SPRoleDefinition);
        }

        /// <summary>
        /// Method to get the <paramref name="name"/> security group in the <paramref name="web"/>.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="groupName">The name of the <see cref="T:Microsoft.SharePoint.SPGroup"/>.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        private static SPGroup _GetSecurityGroup(SPWeb web, string groupName)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return default(SPGroup); }

            SPGroup group = default(SPGroup);

            // Parse the site groups
            foreach (SPGroup siteGroup in web.SiteGroups)
            {
                // See if the group name exists
                if (siteGroup.Name.Equals(groupName, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Set the group
                    group = siteGroup;

                    // Break from the loop
                    break;
                }
            }

            // Return the security group
            return group;
        }

        /// <summary>
        /// Method to processes the batch methods, using the template created in the <see cref="CreateMethodTemplate(SPList)"/> method.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methods">The method templates to process.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static string _ProcessBatchMethods(SPWeb web, string methods)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return string.Empty; }

            // Process the methods
            return web.ProcessBatchData(
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<ows:Batch OnError=\"Continue\">" +
                methods + "</ows:Batch>");
        }

        /// <summary>
        /// Method to remove the <paramref name="groupName"/> from the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="group">The <see cref="T:Microsoft.SharePoint.SPGroup"/> group to remove.</param>
        /// <returns>The <see cref="T:Microsoft.SharePoint.SPGroup"/>.</returns>
        /// <remarks></remarks>
        private static void _RemoveSecurityGroup(SPWeb web, SPGroup group)
        {
            // Ensure the group exists
            if (group != null)
            {
                // Remove the group
                web.RoleAssignments.RemoveById(group.ID);
            }
        }

        /// <summary>
        /// Method to elevate and run the <paramref name="methodToElevate"/> as an administrator, against the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methodToElevate">The method to elevate.</param>
        /// <remarks></remarks>
        private static void _RunAsAdmin(SPWeb web, Action<SPWeb> methodToElevate)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return; }

            // Run with elevated privileges
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                // Create the elevated site object
                using (SPSite elevatedSite = new SPSite(web.Site.ID))
                {
                    // Create the elevated web object
                    using (SPWeb elevatedWeb = elevatedSite.OpenWeb(web.ID))
                    {
                        // Execute the method to elevate
                        methodToElevate(elevatedWeb);
                    }
                }
            });
        }

        /// <summary>
        /// Method to elevate and run the <paramref name="methodToElevate"/> as an administrator, against the <paramref name="site"/>'s root web.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="methodToElevate">The method to elevate.</param>
        /// <param name="inputArgs">The <see cref="InputParameters"/> for <paramref name="methodToElevate"/>.</param>
        /// <returns>Return object from the <paramref name="methodToElevate"/>.</returns>
        /// <remarks></remarks>
        private static object _RunAsAdmin(SPWeb web, Func<InputParameters, object> methodToElevate, params object[] inputArgs)
        {
            object returnVal = default(object);

            // Ensure the web exists
            if (web == null || !web.Exists) { return returnVal; }

            // See if the current user is an admin
            if (web.CurrentUser.IsSiteAdmin)
            {
                // Execute the method to elevate
                returnVal = methodToElevate(new InputParameters(web.Site, web, inputArgs));
            }
            // Else, run with elevated privilieges
            else
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    // Create the elevated site object
                    using (SPSite elevatedSite = new SPSite(web.Site.ID))
                    {
                        // Create the elevated web object
                        using (SPWeb elevatedWeb = elevatedSite.OpenWeb(web.ID))
                        {
                            // Execute the method to elevate
                            returnVal = methodToElevate(new InputParameters(elevatedSite, elevatedWeb, inputArgs));
                        }
                    }
                });
            }

            return returnVal;
        }

        /// <summary>
        /// Method to update the master page.
        /// </summary>
        /// <param name="web">The <see cref="T:Microsoft.SharePoint.SPWeb"/> web.</param>
        /// <param name="customMasterUrl">The custom master page url.</param>
        /// <param name="masterPageUrl">The master page url.</param>
        /// <param name="siteLogoDescription">The site logo description.</param>
        /// <param name="siteLogoUrl">The site logo url.</param>
        /// <param name="uiVersionNumber">The UI Version number.</param>
        /// <param name="updateSubWebsFl">The flag to update all sub-webs.</param>
        private static void _UpdateMasterPage(SPWeb web, string customMasterUrl, string masterPageUrl,
            string siteLogoDescription, string siteLogoUrl, int uiVersionNumber, bool updateSubWebsFl)
        {
            // Ensure the web exists
            if (web == null || !web.Exists) { return; }

            // Ensure the master page urls exists
            if (web.Site.FileExists(customMasterUrl) != null && web.Site.FileExists(masterPageUrl) != null)
            {
                // Set the master page urls
                web.CustomMasterUrl = customMasterUrl;
                web.SiteLogoDescription = siteLogoDescription;
                web.SiteLogoUrl = siteLogoUrl;
                web.MasterUrl = masterPageUrl;
                web.UIVersion = uiVersionNumber;
                web.Update();

                // See if sub-webs exist, and we are updating them.
                if (updateSubWebsFl && web.Webs != null && web.Webs.Count > 0)
                {
                    // Parse all of the sub-webs
                    foreach (SPWeb subWeb in web.Webs)
                    {
                        try
                        {
                            // Update the master page of the sub-web
                            _UpdateMasterPage(subWeb, customMasterUrl, masterPageUrl, siteLogoDescription, siteLogoUrl, uiVersionNumber, true);
                        }
                        finally
                        {
                            // Dispose of the sub-web
                            subWeb.Dispose();
                        }
                    }
                }
            }
        }
        #endregion
    }
}
